package com.micro.ai.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.micro.ai.auth.dto.MenuCreateRequest;
import com.micro.ai.auth.dto.MenuDTO;
import com.micro.ai.auth.dto.MenuUpdateRequest;
import com.micro.ai.auth.dto.VbenMenuDTO;
import com.micro.ai.auth.entity.Menu;
import com.micro.ai.auth.entity.MenuI18n;
import com.micro.ai.auth.mapper.MenuMapper;
import com.micro.ai.auth.mapper.MenuI18nMapper;
import com.micro.ai.auth.service.MenuService;
import com.micro.ai.commons.exception.BusinessException;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单服务实现
 * 
 * @author micro-ai
 * @since 0.0.1
 */
@Slf4j
@Service
public class MenuServiceImpl implements MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private MenuI18nMapper menuI18nMapper;

    @Override
    @Transactional
    public MenuDTO createMenu(MenuCreateRequest request) {
        log.info("创建菜单: tenantId={}, code={}, name={}", request.getTenantId(), request.getCode(), request.getName());

        // 检查菜单编码是否已存在
        if (menuMapper.checkCodeExists(request.getTenantId(), request.getCode(), null) > 0) {
            throw new BusinessException("M0001", "菜单编码已存在");
        }

        // 构建菜单实体
        Menu menu = new Menu();
        BeanUtils.copyProperties(request, menu);
        menu.setId(UUID.randomUUID().toString().replace("-", ""));
        menu.setCreatedAt(LocalDateTime.now());
        menu.setUpdatedAt(LocalDateTime.now());

        // 设置默认值
        if (menu.getLevel() == null) {
            menu.setLevel(0);
        }
        if (menu.getSortOrder() == null) {
            menu.setSortOrder(0);
        }
        if (menu.getStatus() == null) {
            menu.setStatus("active");
        }
        if (menu.getVisible() == null) {
            menu.setVisible(true);
        }
        if (menu.getCache() == null) {
            menu.setCache(true);
        }

        // 如果有父菜单，设置层级
        if (StringUtils.hasText(menu.getParentId())) {
            Menu parentMenu = menuMapper.selectById(menu.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("M0002", "父菜单不存在");
            }
            menu.setLevel(parentMenu.getLevel() + 1);
        }

        // 插入菜单
        menuMapper.insert(menu);

        log.info("创建菜单成功: menuId={}, code={}, name={}", menu.getId(), menu.getCode(), menu.getName());

        // 注意：新权限系统不再自动创建权限点
        // 权限现在通过 role_menus 表的 button_permissions 字段控制
        // API 权限通过 api_permissions 表独立管理

        return convertToDTO(menu);
    }

    @Override
    @Transactional
    public MenuDTO updateMenu(String menuId, MenuUpdateRequest request) {
        log.info("更新菜单: menuId={}", menuId);

        Menu menu = menuMapper.selectById(menuId);
        if (menu == null) {
            throw new BusinessException("M0003", "菜单不存在");
        }

        // 检查菜单编码是否已存在（排除当前菜单）
        if (StringUtils.hasText(request.getCode()) && !request.getCode().equals(menu.getCode())) {
            if (menuMapper.checkCodeExists(menu.getTenantId(), request.getCode(), menuId) > 0) {
                throw new BusinessException("M0001", "菜单编码已存在");
            }
        }

        // 更新菜单信息
        BeanUtils.copyProperties(request, menu, "id", "tenantId", "createdAt");
        menu.setUpdatedAt(LocalDateTime.now());

        // 如果有父菜单，设置层级
        if (StringUtils.hasText(menu.getParentId())) {
            Menu parentMenu = menuMapper.selectById(menu.getParentId());
            if (parentMenu == null) {
                throw new BusinessException("M0002", "父菜单不存在");
            }
            menu.setLevel(parentMenu.getLevel() + 1);
        }

        menuMapper.updateById(menu);

        log.info("更新菜单成功: menuId={}, code={}, name={}", menu.getId(), menu.getCode(), menu.getName());

        return convertToDTO(menu);
    }

    @Override
    @Transactional
    public void deleteMenu(String menuId) {
        log.info("删除菜单（级联删除）: menuId={}", menuId);

        Menu menu = menuMapper.selectById(menuId);
        if (menu == null) {
            throw new BusinessException("M0003", "菜单不存在");
        }

        // 统计删除影响范围
        int childrenCount = menuMapper.countChildren(menuId);
        int rolePermCount = menuMapper.countRoleMenuPermissions(menuId);
        int userPermCount = menuMapper.countUserMenuPermissions(menuId);
        
        log.info("删除影响范围: menuId={}, 子菜单数={}, 角色权限关联数={}, 用户权限关联数={}", 
            menuId, childrenCount, rolePermCount, userPermCount);

        // 1. 递归删除所有子菜单
        if (childrenCount > 0) {
            List<Menu> children = menuMapper.selectByParentId(menuId);
            log.info("开始递归删除 {} 个子菜单", children.size());
            for (Menu child : children) {
                deleteMenuRecursive(child.getId());
            }
        }

        // 2. 删除菜单国际化数据
        menuI18nMapper.deleteByMenuId(menuId);
        log.info("已删除菜单国际化数据: menuId={}", menuId);

        // 3. 删除角色菜单权限关联
        // 注意：数据库外键已设置 ON DELETE CASCADE，这里显式删除以记录日志
        if (rolePermCount > 0) {
            // role_menus 表的外键会自动级联删除
            log.info("数据库将自动删除角色菜单权限关联: menuId={}, count={}", menuId, rolePermCount);
        }

        // 4. 删除用户菜单权限关联
        // 注意：数据库外键已设置 ON DELETE CASCADE，这里显式删除以记录日志
        if (userPermCount > 0) {
            log.info("数据库将自动删除用户菜单权限关联: menuId={}, count={}", menuId, userPermCount);
        }

        // 5. 物理删除菜单本身（真删除）
        int deleteResult = menuMapper.deleteById(menuId);
        
        if (deleteResult == 0) {
            throw new BusinessException("M0007", "删除菜单失败");
        }
        
        log.info("删除菜单成功（级联）: menuId={}, code={}, name={}, 子菜单数={}, deleteResult={}", 
            menuId, menu.getCode(), menu.getName(), childrenCount, deleteResult);
    }

    /**
     * 递归删除子菜单
     */
    private void deleteMenuRecursive(String menuId) {
        Menu menu = menuMapper.selectById(menuId);
        if (menu == null) {
            return;
        }

        // 递归删除子菜单的子菜单
        List<Menu> children = menuMapper.selectByParentId(menuId);
        if (!children.isEmpty()) {
            log.info("递归删除子菜单: parentId={}, 子菜单数={}", menuId, children.size());
            for (Menu child : children) {
                deleteMenuRecursive(child.getId());
            }
        }

        // 删除国际化数据
        menuI18nMapper.deleteByMenuId(menuId);

        // 删除菜单本身
        menuMapper.deleteById(menuId);
        
        log.info("已删除子菜单: menuId={}, code={}, name={}", menuId, menu.getCode(), menu.getName());
    }

    @Override
    public MenuDTO getMenuById(String menuId) {
        Menu menu = menuMapper.selectById(menuId);
        if (menu == null) {
            throw new BusinessException("M0003", "菜单不存在");
        }
        return convertToDTO(menu);
    }

    @Override
    public MenuDTO getMenuByCode(String tenantId, String code) {
        Menu menu = menuMapper.selectByTenantAndCode(tenantId, code);
        if (menu == null) {
            throw new BusinessException("M0003", "菜单不存在");
        }
        return convertToDTO(menu);
    }

    @Override
    public Page<MenuDTO> listMenus(int pageNum, int pageSize, String tenantId, String keyword, String status, String parentId) {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tenant_id", tenantId);
        queryWrapper.isNull("deleted_at");

        if (StringUtils.hasText(keyword)) {
            queryWrapper.and(wrapper -> wrapper
                .like("name", keyword)
                .or()
                .like("code", keyword)
                .or()
                .like("description", keyword)
            );
        }

        if (StringUtils.hasText(status)) {
            queryWrapper.eq("status", status);
        }

        if (StringUtils.hasText(parentId)) {
            queryWrapper.eq("parent_id", parentId);
        } else {
            queryWrapper.isNull("parent_id");
        }

        queryWrapper.orderByAsc("level", "sort_order");

        Page<Menu> page = new Page<>(pageNum, pageSize);
        Page<Menu> result = menuMapper.selectPage(page, queryWrapper);

        // 转换为DTO
        Page<MenuDTO> dtoPage = new Page<>();
        BeanUtils.copyProperties(result, dtoPage, "records");
        dtoPage.setRecords(result.getRecords().stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList()));

        return dtoPage;
    }

    @Override
    public List<MenuDTO> getAllMenus(String tenantId) {
        List<Menu> menus = menuMapper.selectByTenantId(tenantId);
        return menus.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getMenuTree(String tenantId, String parentId, String locale) {
        List<Menu> menus = menuMapper.selectMenuTree(tenantId, parentId);
        List<MenuDTO> menuTree = buildMenuTree(menus, parentId);
        
        // 如果指定了语言，则加载国际化信息
        if (locale != null && !locale.isEmpty()) {
            loadMenuI18n(menuTree, locale);
        }
        
        return menuTree;
    }

    @Override
    public List<MenuDTO> getUserMenus(String userId, String tenantId) {
        List<Menu> menus = menuMapper.selectByUserId(userId, tenantId);
        return menus.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }

    @Override
    public List<MenuDTO> getUserMenuTree(String userId, String tenantId, String locale) {
        List<Menu> menus = menuMapper.selectByUserId(userId, tenantId);
        List<MenuDTO> menuTree = buildMenuTree(menus, null);
        
        // 如果指定了语言，则加载国际化信息
        if (locale != null && !locale.isEmpty()) {
            loadMenuI18n(menuTree, locale);
        }
        
        return menuTree;
    }

    @Override
    public List<VbenMenuDTO> getUserMenuTreeVben(String userId, String tenantId, String locale) {
        // 先获取标准格式菜单树
        List<MenuDTO> menuTree = getUserMenuTree(userId, tenantId, locale);
        
        // 转换为 Vben 格式
        return convertToVbenFormat(menuTree);
    }

    @Override
    public List<MenuDTO> getRoleMenus(String roleId, String tenantId) {
        List<Menu> menus = menuMapper.selectByRoleId(roleId, tenantId);
        return menus.stream()
            .map(this::convertToDTO)
            .collect(Collectors.toList());
    }

    @Override
    public boolean hasMenuAccess(String userId, String menuCode, String tenantId) {
        Menu menu = menuMapper.selectByTenantAndCode(tenantId, menuCode);
        if (menu == null) {
            return false;
        }

        // 检查用户是否有该菜单的访问权限
        List<Menu> userMenus = menuMapper.selectByUserId(userId, tenantId);
        return userMenus.stream()
            .anyMatch(m -> m.getId().equals(menu.getId()));
    }

    @Override
    @Transactional
    public void updateMenuSort(String menuId, Integer sortOrder) {
        menuMapper.updateSortOrder(menuId, sortOrder);
    }

    @Override
    @Transactional
    public void batchUpdateMenuSort(List<String> menuIds, List<Integer> sortOrders) {
        if (menuIds.size() != sortOrders.size()) {
            throw new BusinessException("M0005", "菜单ID和排序数量不匹配");
        }
        menuMapper.batchUpdateSortOrder(menuIds, sortOrders);
    }

    @Override
    @Transactional
    public MenuDTO copyMenu(String sourceMenuId, String targetParentId, String tenantId) {
        Menu sourceMenu = menuMapper.selectById(sourceMenuId);
        if (sourceMenu == null) {
            throw new BusinessException("M0003", "源菜单不存在");
        }

        // 创建新菜单
        Menu newMenu = new Menu();
        BeanUtils.copyProperties(sourceMenu, newMenu, "id", "createdAt", "updatedAt", "deletedAt");
        newMenu.setId(UUID.randomUUID().toString().replace("-", ""));
        newMenu.setCode(sourceMenu.getCode() + "_copy");
        newMenu.setName(sourceMenu.getName() + "_副本");
        newMenu.setParentId(targetParentId);
        newMenu.setCreatedAt(LocalDateTime.now());
        newMenu.setUpdatedAt(LocalDateTime.now());

        menuMapper.insert(newMenu);

        return convertToDTO(newMenu);
    }

    @Override
    @Transactional
    public void moveMenu(String menuId, String targetParentId, String tenantId) {
        Menu menu = menuMapper.selectById(menuId);
        if (menu == null) {
            throw new BusinessException("M0003", "菜单不存在");
        }

        // 检查目标父菜单是否存在
        if (StringUtils.hasText(targetParentId)) {
            Menu targetParent = menuMapper.selectById(targetParentId);
            if (targetParent == null) {
                throw new BusinessException("M0002", "目标父菜单不存在");
            }
        }

        menu.setParentId(targetParentId);
        menu.setUpdatedAt(LocalDateTime.now());
        menuMapper.updateById(menu);
    }

    /**
     * 构建菜单树
     */
    private List<MenuDTO> buildMenuTree(List<Menu> menus, String parentId) {
        Map<String, List<Menu>> menuMap = menus.stream()
            .collect(Collectors.groupingBy(menu -> 
                menu.getParentId() == null ? "root" : menu.getParentId()));

        return buildMenuTreeRecursive(menuMap, parentId == null ? "root" : parentId);
    }

    /**
     * 递归构建菜单树
     */
    private List<MenuDTO> buildMenuTreeRecursive(Map<String, List<Menu>> menuMap, String parentId) {
        List<Menu> children = menuMap.get(parentId);
        if (children == null || children.isEmpty()) {
            return new ArrayList<>();
        }

        return children.stream()
            .map(menu -> {
                MenuDTO dto = convertToDTO(menu);
                dto.setChildren(buildMenuTreeRecursive(menuMap, menu.getId()));
                return dto;
            })
            .collect(Collectors.toList());
    }

    /**
     * 转换为DTO
     * 【重要】将后端菜单数据转换为前端 Vue Router 需要的格式
     */
    private MenuDTO convertToDTO(Menu menu) {
        MenuDTO dto = new MenuDTO();
        
        // 基础信息复制
        dto.setId(menu.getId());
        dto.setTenantId(menu.getTenantId());
        dto.setCode(menu.getCode());
        dto.setType(menu.getType());
        dto.setDescription(menu.getDescription());
        dto.setParentId(menu.getParentId());
        dto.setLevel(menu.getLevel());
        dto.setSortOrder(menu.getSortOrder());
        dto.setPermissionCode(menu.getPermissionCode());
        dto.setStatus(menu.getStatus());
        dto.setVisible(menu.getVisible());
        dto.setCache(menu.getCache());
        dto.setMeta(menu.getMeta());
        dto.setCreatedAt(menu.getCreatedAt() != null ? menu.getCreatedAt().toString() : null);
        dto.setUpdatedAt(menu.getUpdatedAt() != null ? menu.getUpdatedAt().toString() : null);
        
        // 【关键】设置前端路由所需字段
        // 1. name: 路由名称（Vue Router 必需），使用 code 转换为驼峰命名
        if (menu.getCode() != null && !menu.getCode().isEmpty()) {
            dto.setName(convertToCamelCase(menu.getCode()));
        }
        
        // 2. title: 菜单显示名称（从数据库name字段获取中文名称）
        dto.setTitle(menu.getName());  // name字段存储的就是中文显示名称
        
        // 3. path: 路由路径
        dto.setPath(menu.getPath());
        
        // 4. component: 组件路径（确保格式正确：/views/xxx）
        if (menu.getComponent() != null && !menu.getComponent().isEmpty()) {
            String component = menu.getComponent();
            // 移除 /src 前缀，保留 /views 前缀
            if (component.startsWith("/src/views")) {
                component = component.replace("/src/views", "/views");
            } else if (!component.startsWith("/views")) {
                component = "/views" + component;
            }
            dto.setComponent(component);
        } else {
            dto.setComponent(null);
        }
        
        // 5. redirect: 重定向路径
        dto.setRedirect(menu.getRedirect());
        
        // 6. icon: 图标
        dto.setIcon(menu.getIcon());
        
        return dto;
    }
    
    /**
     * 将下划线命名转换为大驼峰命名（PascalCase）
     * 例如：system_user -> SystemUser
     */
    private String convertToCamelCase(String code) {
        if (code == null || code.isEmpty()) {
            return code;
        }
        
        String[] parts = code.split("_");
        StringBuilder result = new StringBuilder();
        
        for (String part : parts) {
            if (part.length() > 0) {
                result.append(Character.toUpperCase(part.charAt(0)));
                if (part.length() > 1) {
                    result.append(part.substring(1).toLowerCase());
                }
            }
        }
        
        return result.toString();
    }

    // ==================== 国际化相关方法实现 ====================

    /**
     * 加载菜单国际化信息
     */
    private void loadMenuI18n(List<MenuDTO> menus, String locale) {
        if (menus == null || menus.isEmpty()) {
            return;
        }
        
        for (MenuDTO menu : menus) {
            // 获取当前菜单的国际化信息
            MenuI18n i18n = menuI18nMapper.selectByMenuIdAndLocale(menu.getId(), locale);
            if (i18n != null) {
                // 创建国际化信息对象
                MenuDTO.MenuI18nInfo i18nInfo = new MenuDTO.MenuI18nInfo();
                i18nInfo.setCurrentLocale(locale);
                
                MenuDTO.MenuI18nContent content = new MenuDTO.MenuI18nContent();
                content.setName(i18n.getName());
                content.setDescription(i18n.getDescription());
                // title 已从数据库删除，使用 name 代替
                content.setTitle(i18n.getName());
                
                i18nInfo.setLocales(Map.of(locale, content));
                menu.setI18n(i18nInfo);
                
                // 如果有国际化内容，则覆盖默认内容
                if (i18n.getName() != null) {
                    menu.setName(i18n.getName());
                }
                if (i18n.getDescription() != null) {
                    menu.setDescription(i18n.getDescription());
                }
            }
            
            // 递归处理子菜单
            if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
                loadMenuI18n(menu.getChildren(), locale);
            }
        }
    }

    @Override
    public List<MenuI18n> getMenuI18n(String menuId) {
        return menuI18nMapper.selectByMenuId(menuId);
    }

    @Override
    public MenuI18n getMenuI18nByLocale(String menuId, String locale) {
        return menuI18nMapper.selectByMenuIdAndLocale(menuId, locale);
    }

    @Override
    @Transactional
    public void saveMenuI18n(String menuId, List<MenuI18n> i18nList) {
        // 先删除现有的国际化信息
        menuI18nMapper.deleteByMenuId(menuId);
        
        // 插入新的国际化信息
        if (i18nList != null && !i18nList.isEmpty()) {
            for (MenuI18n i18n : i18nList) {
                i18n.setId(UUID.randomUUID().toString().replace("-", ""));
                i18n.setMenuId(menuId);
                i18n.setCreatedAt(LocalDateTime.now());
                i18n.setUpdatedAt(LocalDateTime.now());
            }
            menuI18nMapper.batchInsert(i18nList);
        }
    }

    @Override
    @Transactional
    public void deleteMenuI18n(String menuId) {
        menuI18nMapper.deleteByMenuId(menuId);
    }

    @Override
    @Transactional
    public void deleteMenuI18nByLocale(String menuId, String locale) {
        MenuI18n i18n = menuI18nMapper.selectByMenuIdAndLocale(menuId, locale);
        if (i18n != null) {
            menuI18nMapper.deleteById(i18n.getId());
        }
    }

    // ==================== 旧权限系统相关方法（已废弃） ====================
    // 注意：以下方法已不再使用，因为新权限系统采用不同的设计：
    // 1. 菜单权限通过 role_menus 表的 button_permissions 字段控制
    // 2. API 权限通过 api_permissions 表独立管理
    // 3. 不再自动为菜单创建权限点
    // ====================================================================

    /**
     * 转换为 Vben Admin 标准格式
     * 按照 Vben 官方文档要求的数据结构
     */
    private List<VbenMenuDTO> convertToVbenFormat(List<MenuDTO> menuTree) {
        if (menuTree == null || menuTree.isEmpty()) {
            return List.of();
        }
        
        return menuTree.stream()
            .map(this::menuDtoToVbenDto)
            .collect(Collectors.toList());
    }
    
    /**
     * 将 MenuDTO 转换为 VbenMenuDTO
     * 
     * 根据 Vben Admin 文档规范：
     * - 顶层目录菜单不需要 component 字段（会自动使用 BasicLayout）
     * - 只有具体的页面菜单才需要 component 字段
     * - 特殊页面不需要基础布局时，在 meta 中设置 noBasicLayout: true
     */
    private VbenMenuDTO menuDtoToVbenDto(MenuDTO menu) {
        VbenMenuDTO vben = new VbenMenuDTO();
        
        // 1. name: 使用 code 转为 PascalCase（Vue Router 要求）
        vben.setName(convertToCamelCase(menu.getCode()));
        
        // 2. path: 路由路径
        vben.setPath(menu.getPath());
        
        // 3. component: 组件路径（只有页面类型才设置）
        // 目录类型(directory)不需要设置 component
        if ("menu".equals(menu.getType()) && menu.getComponent() != null && !menu.getComponent().isEmpty()) {
            // /views/system/menu/index.vue -> /system/menu/index
            String component = menu.getComponent()
                .replace("/views/", "/")
                .replace(".vue", "");
            vben.setComponent(component);
        }
        
        // 4. redirect: 重定向路径
        // 如果是目录类型且没有设置redirect，自动重定向到第一个子菜单
        if ("directory".equals(menu.getType()) && 
            (menu.getRedirect() == null || menu.getRedirect().isEmpty()) &&
            menu.getChildren() != null && !menu.getChildren().isEmpty()) {
            // 找到第一个可见的子菜单
            MenuDTO firstChild = menu.getChildren().stream()
                .filter(child -> child.getVisible() && "menu".equals(child.getType()))
                .findFirst()
                .orElse(null);
            if (firstChild != null && firstChild.getPath() != null) {
                vben.setRedirect(firstChild.getPath());
            }
        } else {
            vben.setRedirect(menu.getRedirect());
        }
        
        // 5. meta: 元信息
        VbenMenuDTO.VbenMenuMeta meta = new VbenMenuDTO.VbenMenuMeta();
        // title 字段已从数据库删除，DTO 的 title 从 name 获取
        meta.setTitle(menu.getTitle());  // DTO 的 title 在 buildMenuDTO 中已设置为 name
        meta.setIcon(menu.getIcon());
        meta.setOrder(menu.getSortOrder());
        meta.setKeepAlive(menu.getCache());
        meta.setHideInMenu(!menu.getVisible());
        vben.setMeta(meta);
        
        // 6. children: 递归处理子菜单
        if (menu.getChildren() != null && !menu.getChildren().isEmpty()) {
            List<VbenMenuDTO> children = menu.getChildren().stream()
                .map(child -> {
                    VbenMenuDTO childVben = menuDtoToVbenDto(child);
                    // 【关键】子路由的 path 必须是相对路径
                    if (childVben.getPath().startsWith(menu.getPath())) {
                        String relativePath = childVben.getPath()
                            .replace(menu.getPath(), "")
                            .replaceFirst("^/", ""); // 去掉前导斜杠
                        childVben.setPath(relativePath);
                    }
                    return childVben;
                })
                .collect(Collectors.toList());
            vben.setChildren(children);
        }
        
        return vben;
    }
}
